package com.tungse.study.mini_spring.web;

import com.alibaba.fastjson.JSONObject;
import com.tungse.study.mini_spring.MyBeanPostProcessor;
import com.tungse.study.mini_spring.annotation.MyComponent;
import com.tungse.study.mini_spring.interceptor.MyHandlerInterceptorAdapter;
import com.tungse.study.mini_spring.web.annotation.MyController;
import com.tungse.study.mini_spring.web.annotation.MyRequestMapping;
import com.tungse.study.mini_spring.web.annotation.MyRequestParam;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Tungse
 */
@MyComponent
public class DispatcherServlet extends HttpServlet implements MyBeanPostProcessor {

    private final Map<String, WebHandler> handlerMap = new HashMap<>();
    private final List<MyHandlerInterceptorAdapter> interceptorRegistry = new ArrayList<>();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 跳过静态资源请求（如 /static/**, *.js, *.css, *.png 等）
        String path = req.getRequestURI().toLowerCase();
        if (path.startsWith("/static/") || path.matches(".*\\.(js|css|jpg|png|gif|ico|woff2)$")) {
            // 直接返回，不处理
            return;
        }
        WebHandler webHandler = findController(req, resp);
        try {
            if (!preHandle(req, resp, webHandler)) {
                throw new RuntimeException("preHandle return false");
            }
            if (webHandler == null) {
                resp.setContentType("text/html;charset=utf-8");
                resp.getWriter().write("<h1>Error 没有对应请求的处理器</h1> <br/> " + req.getRequestURL().toString());
                return;
            }

            Object[] args = resolveArgs(req, webHandler.getMethod());
            Object controller = webHandler.getController();
            Object result = webHandler.getMethod().invoke(controller, args);

            postHandle(req, resp, webHandler, result);
            switch (webHandler.getResultType()) {
                case JSON: {
                    resp.setContentType("application/json;charset=utf-8");
                    resp.getWriter().write(JSONObject.toJSONString(result));
                }
                case HTML: {
                    resp.setContentType("text/html;charset=utf-8");
                    resp.getWriter().write(result.toString());
                }
                case LOCAL: {
                }
            }
            afterCompletion(req, resp, webHandler, null);
        } catch (Exception e) {
            afterCompletion(req, resp, webHandler, e);
            //throw new RuntimeException(e);
        }
    }

    public void addInterceptors(MyHandlerInterceptorAdapter interceptor) {
        interceptorRegistry.add(interceptor);
    }

    private Boolean preHandle(HttpServletRequest req, HttpServletResponse resp, WebHandler webHandler) {
        for (MyHandlerInterceptorAdapter myHandlerInterceptorAdapter : interceptorRegistry) {
            if (!myHandlerInterceptorAdapter.preHandle(req, resp, webHandler)) {
                return false;
            }
        }
        return true;
    }

    private void postHandle(HttpServletRequest req, HttpServletResponse resp, WebHandler webHandler, Object result) {
        for (MyHandlerInterceptorAdapter myHandlerInterceptorAdapter : interceptorRegistry) {
            myHandlerInterceptorAdapter.postHandle(req, resp, webHandler, result);
        }
    }

    private void afterCompletion(HttpServletRequest req, HttpServletResponse resp, WebHandler webHandler, Exception ex) {
        for (MyHandlerInterceptorAdapter myHandlerInterceptorAdapter : interceptorRegistry) {
            myHandlerInterceptorAdapter.afterCompletion(req, resp, webHandler, ex);
        }
    }

    private Object[] resolveArgs(HttpServletRequest req, Method method) {
        Parameter[] parameters = method.getParameters();
        Object[] args = new Object[parameters.length];

        for (int i=0; i<parameters.length; i++) {
            Parameter parameter = parameters[i];

            MyRequestParam annotation = parameter.getAnnotation(MyRequestParam.class);
            String paramName = annotation==null?parameter.getName() : annotation.value();
            Object param = req.getParameter(paramName);

            if(parameter.getType().isAssignableFrom(String.class)) {
                args[i] = String.valueOf(param);
            } else if (parameter.getType().isAssignableFrom(Integer.class)) {
                args[i] = Integer.valueOf(param.toString());
            } else {
                args[i] = null;
            }
        }
        return args;
    }

    private WebHandler findController(HttpServletRequest req, HttpServletResponse resp) {

        return handlerMap.get(req.getRequestURI());

    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean.getClass().isAssignableFrom(MyController.class)) {
            return bean;
        }
        MyRequestMapping annotation = bean.getClass().getAnnotation(MyRequestMapping.class);
        final String classUuri = annotation != null? annotation.value() : "";
        Arrays.stream(bean.getClass().getDeclaredMethods())
            .filter(e -> e.isAnnotationPresent(MyRequestMapping.class))
            .forEach(e -> {
                MyRequestMapping methodAnnotation = e.getAnnotation(MyRequestMapping.class);
                String key = classUuri.concat(methodAnnotation.value()) ;
                WebHandler webHandler = new WebHandler(bean, e);
                if(handlerMap.put(key, webHandler) != null) {
                    throw  new RuntimeException("重复的请求映射" + key);
                };
            });
        return bean;
    }
}
